/**
 * 
 */
package spitfire.ksim.algorithm;

import java.util.List;

/**
 * @author Adam
 *
 */
public class RuleExtractionImpl implements RuleExtractionAlgorithm {

	@Override
	public FuzzyRule extractRule(List<Long> timeStampList, List<Double> dataList) {
		FuzzyRule rule = new FuzzyRule();
		double rMax = 0;
		double rMin = Double.MAX_VALUE;
		for (int i = 0; i < timeStampList.size(); i++) {
			if (dataList.get(i) != null) {
				if (dataList.get(i) > rMax) {
					rMax = dataList.get(i);
				}
				if (dataList.get(i) < rMin) {
					rMin = dataList.get(i);
				}
			}
			rule.add((Double)timeStampList.get(i).doubleValue(), dataList.get(i));
		}
		rule.setrMax(rMax);
		rule.setrMin(rMin);
		return rule;
	}

	
//	@Override
//	public FuzzyRule extractRule(List<Long> timeStampList,
//			List<Double> dataList) {
//		
////		List<Long> timeStampL = new ArrayList<Long>(timeStampList); 
//		// Check data adequacy
////		if (!PreprocAndValidationAlgorithm.procAndValid(timeStampL, dataList)) {
////			System.out.println("Not enough data for Rule Extraction");
////			return null;
////		}
//
//		Double[] raw = dataList.toArray(new Double[dataList.size()]);
//		// Identify the value range
//		double rawMax = Collections.max(dataList);
//		double rawMin = Collections.min(dataList);
//		double rawRange = rawMax - rawMin;
//		// Max-Min normalize raw data
//		double[] normRaw = new double[raw.length];
//		for (int i=0; i<normRaw.length; i++) {
//			normRaw[i] = (raw[i] - rawMin) / rawRange;
//		}
//		
//		//Calculate neighborhood density curve of data
//		double ra = 0.5;
//		double alpha = 4/ra/ra;
//		double ndc[] = new double[normRaw.length];
//		for (int i=0; i<normRaw.length; i++) {
//			ndc[i] = 0;
//			for (int j=0; j<normRaw.length; j++) {
//				double d = Math.abs(normRaw[i]-normRaw[j]);
//				ndc[i] += Math.exp(-alpha*d*d);
//			}
//		}
//		
//		// Max-Min normalize neighborhood density
//		double ndcMax = Double.MIN_VALUE;
//		double ndcMin = Double.MAX_VALUE;
//		for (int i=0; i<ndc.length; i++) {
//			if (ndcMax < ndc[i]) ndcMax = ndc[i];
//			if (ndcMin > ndc[i]) ndcMin = ndc[i];
//		}
//		double ndcRange = ndcMax - ndcMin;
//		for (int i=0; i<ndc.length; i++) {
//			ndc[i] = (ndc[i] - ndcMin) / ndcRange;
//		}
//
//		//Discretize the neighborhood density curve
//		int dSize = 100;
//		double delta = rawRange / dSize;
//
//		double dndcX[] = new double[dSize];
//		double dndcXN[] = new double[dSize];
//		double dndcY[] = new double[dSize];
//		int dndcC[] = new int[dSize];
//		for (int i=0; i<dSize; i++) {
//			dndcX[i] = rawMin + delta/2 + i*delta;
//			dndcXN[i] = (1/(double)dSize)/2 + (double)i/(double)dSize;
//			dndcY[i] = 0;
//			dndcC[i] = 0;
//		}
//		for (int i=0; i<ndc.length; i++) {
//			int dcount = (int)((raw[i] - rawMin) / delta);
//			if (dcount >= dSize) dcount = dSize-1;
//			dndcY[dcount] += ndc[i];
//			dndcC[dcount]++;
//		}
//		for (int i=0; i<dndcX.length; i++) {
//			if (dndcC[i] > 0) {
//				dndcY[i] /= dndcC[i];
//			}
//		}
//
//		/*------ Linearize the discrete neighborhood density curve ------ */
//		TList vx = new TList();
//		//			TList vxN = new TList();
//		TList vy = new TList();
//		TList dy = new TList();
//
//		//Eliminate no-data points
//		int i1 = 0;
//		while (dndcC[i1] <= 0) i1++;
//		vx.enList(Double.valueOf(dndcX[i1]));
//		vy.enList(Double.valueOf(dndcY[i1]));
//		dy.enList(Double.valueOf(0));
//		for (int i2=i1+1; i2<dndcX.length; i2++) if (dndcC[i2] > 0) {
//			vx.enList(Double.valueOf(dndcX[i2]));
//			vy.enList(Double.valueOf(dndcY[i2]));
//			double d = (dndcY[i2] - dndcY[i1]) / (dndcXN[i2] - dndcXN[i1]);
//			dy.enList(Double.valueOf(d));
//			i1 = i2;
//		}
//
//		//Linearize the has-data points
//		//bugfix: dy can be of size 1, leading to OutOfBoundException
////		if (vx.len() < 2 || vy.len() < 2 || dy.len() < 2) { // temporary solution
////			return null;
////		}
//		FuzzyRule rule = new FuzzyRule();
//		rule.setrMax(rawMax);
//		rule.setrMin(rawMin);
//		rule.add((Double)vx.get(0), (Double)vy.get(0));
//		if (dy.len() > 1) {
//			double thSlope = 1; // PI/4
//			double slope1 = ((Double)dy.get(1)).doubleValue();
//			for (int i=2; i<dy.len(); i++) {
//				double slope2 = ((Double)dy.get(i)).doubleValue();
//				double dSlope = Math.abs(slope2-slope1);
//				if (dSlope >= thSlope) {
//					rule.add((Double)vx.get(i-1), (Double)vy.get(i-1));
//					slope1 = slope2;
//				}
//			}
//			rule.add((Double)vx.get(vx.len()-1), (Double)vy.get(vy.len()-1));
//			return rule;
//		} else {
//			// Not generate a rule if len <=1
//			return null;
//		}
//	}
}
